[CF364D]Ghd

2020-03-06
Codeforces

题意

在$\{a_i\}$中,选出至少$\frac{(n+1)}{2}$个数,使得它们的gcd最大,输出最大值

$n\leq 10^6,a_i\leq 10^{12}$

题解

如果假定某个数在答案中,统计每个因数在它与所有数中出现的次数,从大到小遍历就能确定这种情况下的最优解

统计因数的时候,为了保证效率,可以先只统计gcd本身,然后再统计gcd的因子

由于选出的数超过一半,故每个数在答案中的概率为$\frac{1}{2}$,跑10次就差不多了$\color{Orange}{看脸过题?}$

调试记录

vector没有用long long

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
#include <cstring>
#define LL long long
const int maxn = 1e6 + 5;
using namespace std;
LL a[maxn]; int n;
vector <LL> v;
void split(LL x){
v.clear();
for (LL i = 1; i * i <= x; i++){
if (x % i != 0) continue;
v.push_back(i);
if (i * i != x) v.push_back(x / i);
} sort(v.begin(), v.end());
}
LL _gcd(LL x, LL y){
return (!y) ? x : _gcd(y, x % y);
}
int cnt[10005]; LL ans = 0;
LL max(LL x, LL y){
return x < y ? y : x;
}
int main(){
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld", a + i);
for (int T = 0; T < 10; T++){
int u = rand() * rand() % n + 1;
split(a[u]); memset(cnt, 0, sizeof cnt);
for (int i = 1; i <= n; i++){
LL g = _gcd(a[i], a[u]);
vector<LL>::iterator it = lower_bound(v.begin(), v.end(), g);
if (it == v.end()) continue;
cnt[it - v.begin()]++;
}
for (int i = 0; i < v.size(); i++)
for (int j = i + 1; j < v.size(); j++)
if (v[j] % v[i] == 0) cnt[i] += cnt[j];
for (int i = v.size() - 1; i >= 0; i--){
if (cnt[i] >= (n + 1) / 2){
ans = max(ans, v[i]);
break;
}
}
} printf("%lld\n", ans);
return 0;
}